﻿using System;
using System.Collections.ObjectModel;

using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using System.Collections.Generic;

namespace mvcForum.Tests.WebUI {

	public static class ForumAdminExtensions {

		public static void CreateBoard(this IWebDriver driver, String boardName, String siteName, String siteDescription) {
			driver.VisitURL("forumadmin", "stats");
			driver.Wait(1);

			IWebElement addLink = driver.FindElement(By.LinkText("Add Board"));
			addLink.Click();

			driver.InsertText("Name", boardName);
			driver.InsertText("SiteName", siteName);
			driver.InsertText("SiteDescription", siteDescription);

			IWebElement createLink = driver.FindElement(By.LinkText("Create"));
			createLink.Click();
		}

		public static void CreateCategory(this IWebDriver driver, String boardName, String categoryName, Int32 sortOrder) {
			driver.EditBoard(boardName);
			driver.Wait(1);

			IWebElement addLink = driver.FindElement(By.LinkText("Add Category"));
			addLink.Click();

			IWebElement modal = driver.FindElement(By.Id("newcategorymodal"));

			IWebElement nameField = modal.FindElement(By.Name("Name"));
			driver.InsertText(nameField, categoryName);

			IWebElement sortOrderField = modal.FindElement(By.Name("SortOrder"));
			driver.InsertText(sortOrderField, sortOrder.ToString());

			IWebElement createLink = modal.FindElement(By.LinkText("Create"));
			createLink.Click();
		}

		public static void CreateForum(this IWebDriver driver, String boardName, String categoryName, String forumName, String description, Int32 sortOrder) {
			driver.EditCategory(boardName, categoryName);
			driver.Wait(1);

			IWebElement addLink = driver.FindElement(By.LinkText("Add Forum"));
			addLink.Click();

			IWebElement modal = driver.FindElement(By.Id("newforummodal"));

			IWebElement nameField = modal.FindElement(By.Name("Name"));
			driver.InsertText(nameField, forumName);

			IWebElement descriptionField = modal.FindElement(By.Name("Description"));
			driver.InsertText(descriptionField, description);

			IWebElement sortOrderField = modal.FindElement(By.Name("SortOrder"));
			driver.InsertText(sortOrderField, sortOrder.ToString());

			IWebElement createLink = modal.FindElement(By.LinkText("Create"));
			createLink.Click();
		}

		public static void CreateSubForum(this IWebDriver driver, String boardName, String categoryName, String parentForumName, String forumName, String description, Int32 sortOrder) {
			driver.EditForum(boardName, categoryName, parentForumName);
			driver.Wait(1);

			IWebElement addLink = driver.FindElement(By.LinkText("Add Forum"));
			addLink.Click();

			IWebElement modal = driver.FindElement(By.Id("newforummodal"));

			IWebElement nameField = modal.FindElement(By.Name("Name"));
			driver.InsertText(nameField, forumName);

			IWebElement descriptionField = modal.FindElement(By.Name("Description"));
			driver.InsertText(descriptionField, description);

			IWebElement sortOrderField = modal.FindElement(By.Name("SortOrder"));
			driver.InsertText(sortOrderField, sortOrder.ToString());

			IWebElement createLink = modal.FindElement(By.LinkText("Create"));
			createLink.Click();
		}

		public static void EditForum(this IWebDriver driver, String boardName, String categoryName, String forumName) {
			driver.EditCategory(boardName, categoryName);
			driver.Wait(1);

			IWebElement row = driver.FindForumRow(forumName);
			if (row == null) {
				throw new ApplicationException("Forum not found");
			}

			row.FindElement(By.LinkText("Edit")).Click();

			WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, 10));
			wait.Until(drv => drv.FindElement(By.Id("forumsec")));
			driver.Wait(1);
		}

		public static void EditSubForum(this IWebDriver driver, String boardName, String categoryName, String forumName, String subForumName) {
			driver.EditForum(boardName, categoryName, forumName);
			driver.Wait(1);

			IWebElement row = driver.FindForumRow(subForumName);
			if (row == null) {
				throw new ApplicationException("Forum not found");
			}

			row.FindElement(By.LinkText("Edit")).Click();

			WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, 10));
			wait.Until(drv => drv.FindElement(By.Id("forumsec")));
			driver.Wait(1);
		}

		public static void EditCategory(this IWebDriver driver, String boardName, String categoryName) {
			driver.EditBoard(boardName);
			driver.Wait(1);

			IWebElement row = driver.FindCategoryRow(categoryName);
			if (row == null) {
				throw new ApplicationException("Category not found");
			}

			row.FindElement(By.LinkText("Edit")).Click();

			WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, 10));
			wait.Until(drv => drv.FindElement(By.Id("categorysec")));
			driver.Wait(1);
		}

		public static void EditBoard(this IWebDriver driver, String boardName) {
			driver.VisitURL("forumadmin", "stats");

			IWebElement row = FindBoardRow(driver, boardName);
			if (row == null) {
				throw new ApplicationException("Board not found");
			}

			row.FindElement(By.LinkText("Edit")).Click();

			WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, 10));
			wait.Until(drv => drv.FindElement(By.Id("boardsec")));
			driver.Wait(1);
		}

		public static void AddGroupToUser(this IWebDriver driver, String username, String groupName) {
			driver.VisitURL("forumadmin/user", "users");

			Boolean found = false;
			ReadOnlyCollection<IWebElement> rows = driver.FindElement(By.Id("userlist")).FindElements(By.XPath("table/tbody/tr"));
			foreach (IWebElement row in rows) {
				if (row.FindElements(By.TagName("td"))[0].Text == username) {
					found = true;
					row.FindElement(By.LinkText("Edit")).Click();
					break;
				}
			}

			if (!found) {
				//TODO:
				throw new ApplicationException("User not found!");
			}

			driver.Wait(1);

			driver.FindElement(By.LinkText("Add Group")).Click();

			WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, 10));
			wait.Until(drv=>drv.FindElement(By.Id("newgroup")));

			driver.SelectOption("groupname", "Moderator");

			driver.FindElement(By.LinkText("Create")).Click();
		}

		public static void SetStandardAccess(this IWebDriver driver, String boardName, String categoryName, String forumName, String subForumName) {
			driver.EditSubForum(boardName, categoryName, forumName, subForumName);

			ReadOnlyCollection<IWebElement> groups = driver.FindElement(By.Id("access")).FindElements(By.XPath("table/tbody/tr"));

			Dictionary<String, String> mapper = new Dictionary<String, String>();
			mapper.Add("Administrator", "Admin access");
			mapper.Add("Guest", "Readonly access");
			mapper.Add("Member", "Member access");
			mapper.Add("Moderator", "Moderator access");

			foreach (IWebElement group in groups) {
				if (mapper.ContainsKey(group.FindElements(By.TagName("td"))[0].Text)) {
					driver.SelectOption(group.FindElements(By.TagName("td"))[1].FindElement(By.TagName("select")).FindElements(By.TagName("option")), mapper[group.FindElements(By.TagName("td"))[0].Text]);
				}
				group.FindElement(By.LinkText("Update")).Click();
			}
		}

		public static void SetStandardAccess(this IWebDriver driver, String boardName, String categoryName, String forumName) {
			driver.EditForum(boardName, categoryName, forumName);

			ReadOnlyCollection<IWebElement> groups = driver.FindElement(By.Id("access")).FindElements(By.XPath("table/tbody/tr"));

			Dictionary<String, String> mapper = new Dictionary<String, String>();
			mapper.Add("Administrator", "Admin access");
			mapper.Add("Guest", "Readonly access");
			mapper.Add("Member", "Member access");
			mapper.Add("Moderator", "Moderator access");

			foreach (IWebElement group in groups) {
				if (mapper.ContainsKey(group.FindElements(By.TagName("td"))[0].Text)) {
					driver.SelectOption(group.FindElements(By.TagName("td"))[1].FindElement(By.TagName("select")).FindElements(By.TagName("option")), mapper[group.FindElements(By.TagName("td"))[0].Text]);
				}
				group.FindElement(By.LinkText("Update")).Click();
			}
		}

		/// <summary>
		/// Prerequisite - the driver is already on the /forumadmin page
		/// </summary>
		/// <param name="driver"></param>
		/// <param name="name"></param>
		/// <returns></returns>
		public static IWebElement FindBoardRow(this IWebDriver driver, String name) {
			IWebElement boardRow = null;
			ReadOnlyCollection<IWebElement> rows = driver.FindBoardRows();
			Boolean found = false;
			foreach (IWebElement row in rows) {
				foreach (IWebElement column in row.FindElements(By.XPath("td"))) {
					if (column.Text == name) {
						found = true;
						boardRow = row;
						break;
					}
				}

				if (found) {
					break;
				}
			}

			return boardRow;
		}

		/// <summary>
		/// Prerequisite - the driver is already on a /forumadmin/board/update page
		/// </summary>
		/// <param name="driver"></param>
		/// <param name="name"></param>
		/// <returns></returns>
		public static IWebElement FindCategoryRow(this IWebDriver driver, String name) {
			IWebElement categoryRow = null;
			ReadOnlyCollection<IWebElement> rows = driver.FindCategoryRows();
			Boolean found = false;
			foreach (IWebElement row in rows) {
				foreach (IWebElement column in row.FindElements(By.XPath("td"))) {
					if (column.Text == name) {
						found = true;
						categoryRow = row;
						break;
					}
				}

				if (found) {
					break;
				}
			}

			return categoryRow;
		}

		/// <summary>
		/// Prerequisite - the driver is already on a /forumadmin/category/update or /forumadmin/forum/update page
		/// </summary>
		/// <param name="driver"></param>
		/// <param name="name"></param>
		/// <returns></returns>
		public static IWebElement FindForumRow(this IWebDriver driver, String name) {
			IWebElement forumRow = null;
			ReadOnlyCollection<IWebElement> rows = driver.FindForumRows();
			Boolean found = false;
			foreach (IWebElement row in rows) {
				foreach (IWebElement column in row.FindElements(By.XPath("td"))) {
					if (column.Text == name) {
						found = true;
						forumRow = row;
						break;
					}
				}

				if (found) {
					break;
				}
			}

			return forumRow;
		}

		public static ReadOnlyCollection<IWebElement> FindBoardRows(this IWebDriver driver) {
			return FindRows(driver, "boards");
		}

		public static ReadOnlyCollection<IWebElement> FindCategoryRows(this IWebDriver driver) {
			return FindRows(driver, "categories");
		}

		public static ReadOnlyCollection<IWebElement> FindForumRows(this IWebDriver driver) {
			return FindRows(driver, "forums");
		}

		private static ReadOnlyCollection<IWebElement> FindRows(IWebDriver driver, String id) {
			return driver.FindElement(By.Id(id)).FindElements(By.XPath("table/tbody/tr"));
		}
	}
}